use std::ffi::c_void;
use serde::{Deserialize, Serialize};
use tokio::time::{sleep, Duration};
use windows::Win32::{
    Foundation::HGLOBAL,
    System::{
        DataExchange::CloseClipboard,
        Memory::{GlobalLock, GlobalUnlock},
    },
    UI::Input::KeyboardAndMouse::{
        SendInput, INPUT, INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYBD_EVENT_FLAGS, KEYEVENTF_KEYUP,
        KEYEVENTF_UNICODE, VIRTUAL_KEY, VK_RETURN,
    },
};
use windows::Win32::{
    Foundation::HWND,
    System::DataExchange::{GetClipboardData, OpenClipboard},
};



// AI请求相关结构体
#[derive(Serialize, Deserialize)]
struct ChatMessage {
    role: String,
    content: String,
}

#[derive(Serialize, Deserialize)]
struct ChatRequest {
    model: String,
    messages: Vec<ChatMessage>,
}

#[derive(Deserialize)]
struct Choice {
    message: ChatMessage,
}

#[derive(Deserialize)]
struct ChatResponse {
    choices: Vec<Choice>,
}

fn get_clipboard() -> Result<Vec<u16>, &'static str> {
    const CF_UNICODETEXT: u32 = 13;
    let mut result: Vec<u16> = vec![];

    //参考 https://learn.microsoft.com/zh-cn/windows/win32/dataxchg/using-the-clipboard#pasting-information-from-the-clipboard
    unsafe {
        OpenClipboard(HWND(0)).or(Err("打开剪切板错误"))?;
        let hglb = GetClipboardData(CF_UNICODETEXT).map_err(|_| {
            if let Err(_) = CloseClipboard() {
                return "关闭剪切板失败";
            }
            "获取剪切板数据错误"
        })?;
        let locker = HGLOBAL(hglb.0 as *mut c_void);
        let raw_data = GlobalLock(locker);
        let data = raw_data as *const u16;
        let mut i = 0usize;

        loop {
            let item = *data.add(i);
            i += 1;
            if item == 0 {
                break;
            }
            if item == 13 {
                //舍弃'\r'
                continue;
            }
            result.push(item);
        }

        GlobalUnlock(locker).map_err(|_| {
            if let Err(_) = CloseClipboard() {
                return "关闭剪切板失败";
            }
            "解除剪切板锁定失败"
        })?;
        CloseClipboard().or(Err("关闭剪切板失败"))?;
    }
    return Ok(result);
}

// 粘贴命令，使用传入的内容
#[tauri::command]
pub async fn paste(content: String, stand: u32, float: u32) -> Result<(), &'static str> {
    let utf16_units: Vec<u16> = content.encode_utf16().collect();
    
    for item in utf16_units {
        if item == 10 {
            //必须特别处理回车
            let input = [
                INPUT {
                    r#type: INPUT_KEYBOARD,
                    Anonymous: INPUT_0 {
                        //参考 https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/ns-winuser-keybdinput
                        ki: KEYBDINPUT {
                            wVk: VK_RETURN,
                            wScan: 0,
                            dwFlags: KEYBD_EVENT_FLAGS(0),
                            time: 0,
                            dwExtraInfo: 0,
                        },
                    },
                },
                INPUT {
                    r#type: INPUT_KEYBOARD,
                    Anonymous: INPUT_0 {
                        ki: KEYBDINPUT {
                            wVk: VK_RETURN,
                            wScan: 0,
                            dwFlags: KEYEVENTF_KEYUP,
                            time: 0,
                            dwExtraInfo: 0,
                        },
                    },
                },
            ];
            unsafe {
                SendInput(&input, std::mem::size_of::<INPUT>() as i32);
            }
        } else {
            let input = [INPUT {
                r#type: INPUT_KEYBOARD,
                Anonymous: INPUT_0 {
                    ki: KEYBDINPUT {
                        wVk: VIRTUAL_KEY(0),
                        wScan: item,
                        dwFlags: KEYEVENTF_UNICODE,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            }];
            unsafe {
                SendInput(&input, std::mem::size_of::<INPUT>() as i32);
            }
        };

        let random = rand::random::<u32>();
        sleep(Duration::from_millis((stand + random % float) as u64)).await;
    }

    return Ok(());
}

// 调用DeepSeek API的命令
#[tauri::command]
pub async fn ask_ai(question: String, profession: String, subject: String, api_key: String) -> Result<String, String> {
    let client = reqwest::Client::new();
    
    // 构建系统提示
    let system_prompt = if profession.is_empty() && subject.is_empty() {
        // 如果专业和科目都为空，使用通用提示
        "你是一个知识渊博的助手。请帮我回答问题，回答应当精简并且不包含markdown的加粗格式，不要有过多的总结和解释内容。".to_string()
    } else if profession.is_empty() {
        // 如果只有科目
        format!(
            "你是一个{}领域的专家。现在，我有一个有关{}的问题，请帮我进行正确并且完善的解答。输出的内容应当精简并且不包含markdown的加粗格式，不要有过多的总结和解释内容。",
            subject, subject
        )
    } else if subject.is_empty() {
        // 如果只有专业
        format!(
            "你是一个优秀的{}专业人士。请帮我解答问题，回答应当精简并且不包含markdown的加粗格式，不要有过多的总结和解释内容。",
            profession
        )
    } else {
        // 两者都有
        format!(
            "你是一个优秀的{}专业人士，专攻{}领域。现在，我有一个有关{}的问题，请帮我进行正确并且完善的解答。输出的内容应当精简并且不包含markdown的加粗格式，不要有过多的总结和解释内容。",
            profession, subject, subject
        )
    };
    
    // 创建系统消息和用户问题
    let messages = vec![
        ChatMessage {
            role: "system".to_string(),
            content: system_prompt,
        },
        ChatMessage {
            role: "user".to_string(),
            content: question,
        },
    ];

    // 构建请求体
    let request_body = ChatRequest {
        model: "deepseek-chat".to_string(),
        messages,
    };

    // 发送请求到DeepSeek API
    let response = client
        .post("https://api.deepseek.com/v1/chat/completions")
        .header("Content-Type", "application/json")
        .header("Authorization", format!("Bearer {}", api_key))
        .json(&request_body)
        .send()
        .await
        .map_err(|e| format!("API请求失败: {}", e))?;

    if !response.status().is_success() {
        let error_text = response.text().await.unwrap_or_else(|_| "无法获取错误详情".to_string());
        return Err(format!("API返回错误: {}", error_text));
    }

    // 解析API响应
    let response_data: ChatResponse = response
        .json()
        .await
        .map_err(|e| format!("解析API响应失败: {}", e))?;

    // 提取AI的回答
    if let Some(choice) = response_data.choices.first() {
        Ok(choice.message.content.clone())
    } else {
        Err("API返回的响应中没有找到答案".to_string())
    }
}
